home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
preccx
/
prccx240.lha
/
cc.c
< prev
next >
Wrap
Text File
|
1992-08-21
|
4KB
|
231 lines
/*
parser suite - and / or / nothing / something parsers
parser = [token] -> ([token],status)
implemented as sideeffecting on [token], returns status.
*/
# include "cc.h"
STATUS p_andparse0 (p, q)
/*
Serial composition of parsers. Does
first p then q. Put p's instructions on the
top of the program stack, then layer q's above it.
This version has full rewind of the input stream on
failure, but this can be altered to single token
lookahead by deleting the line of code marked.
*/
PARSER p, q;
{
static status tok; /* why can't this be static? */
MARK;
tok = p ();
if (BADSTATUS (tok)){ /* error */
RELEASE;
return tok;
}
tok = q ();
if (BADSTATUS (tok)) /* error */
{
REWIND; /* remove this line for 1-token LA parsing */
return tok;
}
pushDECR;
RELEASE;
return tok; /* succeed */
}
STATUS p_orparse0 (p, q)
/*
alternate composition of parsers. Tries p first,
and if it doesnt work, tries q. Code corresponding
to the successful parse is placed on the program stack.
If both fail, the routine relies on p and q's auto-rewind
mechanisms to do the rewind for it.
*/
PARSER p, q;
{
static status tok; /* I don't see why this can't be static */
tok = p ();
if (BADSTATUS (tok)) /* error */
tok = q (); /* retry */
return tok; /* whatever */
}
STATUS p_many0 (p)
/*
parser which tries p any number of times
until p fails, but returns success anyhow.
*/
PARSER p;
{
int repeat = 0;
while (GOODSTATUS(p ()))
repeat++;
switch(repeat){
case 0: pushINCR; break;
case 1: break;
default:pushMANIP(-(repeat-1)); break;
}
return (SUCCESS);
}
STATUS p_iter0 (repeat, p)
/*
parser which tries p repeat number of times exactly
*/
PARSER p;
int repeat;
{
static int k;
static status tok;
MARK;
k = repeat;
while (k-->0) {
tok = p ();
if (BADSTATUS(tok)) {
REWIND;
return tok;
}
}
switch(repeat){
case 0: pushINCR; break;
case 1: break;
default:pushMANIP(-(repeat-1)); break;
}
RELEASE;
return tok;
}
STATUS p_some0 (p)
/*
At least one repetition of parser p
*/
PARSER p;
{
status tok;
tok = p ();
if (GOODSTATUS(tok)){
tok = p_many0 (p);
pushDECR; /* bound to succeed */
return(tok);
}
return tok;
}
STATUS p_option0 (p)
/* optionally p */
PARSER p;
{
static status tok;
tok = p();
if (GOODSTATUS(tok))
return tok;
pushINCR;
return(SUCCESS);
}
STATUS p_range0 (p)
/*
checks whether *pstr satisfies predicate p.
p must take a TOKEN as arg. That is a mistake. It should be
an int (a PARAM).
*/
PREDICATE *p;
{
VALUE v;
if ((*p) (*pstr))
{
v = lvbuff[pstr-buffer];
MOVEON;
pushVALUE(v);
return (OK(v));
}
return (FAILURE);
}
STATUS p_attach (p,f)
PARSER p;
ACTION f;
{
static status tok;
tok = p ();
if (GOODSTATUS(tok)) {
pushACTION(f);
return tok;
}
return tok;
}
STATUS p_prepend (f,p)
PARSER p;
ACTION f;
{
static status tok;
MARK;
pushACTION(f);
tok = p ();
if (GOODSTATUS(tok)) {
RELEASE;
return tok;
}
REWIND;
return tok;
}
STATUS p_hidden0 (p)
PARSER p;
/*
parser which tries p, but doesnt moveon, just reports the result
of p.
*/
{
static status tok;
MARK;
tok = p ();
REWIND;
if(GOODSTATUS(tok)) { /* we have to show we were here to keep in V(n) step */
pushVALUE(tok);
return tok;
}
return tok;
}